# pragma once 

#include <string>
#include <cstdint>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include <cstring>
#include <stdexcept>
#include <chrono>
#include <thread>
#include <errno.h>

namespace can
{
    // 字节序枚举
    enum class Endianness {
        LITTLE, // 小端
        BIG     // 大端
    };
    
    // 将CAN原始数据转为无符号整数
    uint64_t to_uint(const uint8_t* data, size_t start, size_t length, Endianness endian) {
        if (length == 0 || start + length > 8) 
        {
            throw std::invalid_argument("Length must be between 1 and 8");
        }
    
        uint64_t result = 0;
        if (endian == Endianness::LITTLE) {
            for (size_t i = start; i < start + length; ++i) 
            {
                result |= static_cast<uint64_t>(data[i]) << (i * 8);
            }
        } 
        else 
        { // BIG
            for (size_t i = start; i < start + length; ++i) 
            {
                result = (result << 8) | data[i];
            }
        }
        return result;
    }
    
    // 将CAN原始数据转为有符号整数
    int64_t to_int(const uint8_t* data, size_t start, size_t length, Endianness endian) {
        uint64_t uval = to_uint(data, start, length, endian);
        
        // 计算符号位掩码
        uint64_t mask = 1ULL << (length * 8 - 1);
        
        // 如果符号位为1，转换为补码
        if (uval & mask) {
            return static_cast<int64_t>(uval | (~((1ULL << (length * 8)) - 1)));
        }
        
        return static_cast<int64_t>(uval);
    }
    
    template <typename T>
    typename std::enable_if<std::is_integral<T>::value, double>::type
    unpack(T raw, double scale, double offset) 
    {
        return (double)raw * scale + offset;
    }
    
    template<typename T>
    T pack(double value, double scale, double offset) 
    {
        static_assert(std::is_integral_v<T>, "T must be integer type");
        
        double raw_double = (value - offset) / scale;
        
        // 范围裁剪
        T min_val = std::numeric_limits<T>::min();
        T max_val = std::numeric_limits<T>::max();
        if (raw_double < min_val) raw_double = min_val;
        if (raw_double > max_val) raw_double = max_val;
        
        T raw = static_cast<T>(raw_double);

        return raw;
    }

    template<typename T>
    void to_message(const T& value, uint8_t* out, Endianness endian) {
        static_assert(std::is_integral_v<T>, "T must be integer type");
        
        const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
        size_t size = sizeof(T);
        
        if (endian == Endianness::LITTLE) 
        {
            for (size_t i = 0; i < size; ++i) 
            {
                out[i] = bytes[i];
            }
        } 
        else 
        {
            for (size_t i = 0; i < size; ++i) 
            {
                out[i] = bytes[size - 1 - i];
            }
        }
    }
    
    class controller {
    private:
        int m_sock;          // CAN socket文件描述符
        std::string m_interface;  // CAN接口名称(如"can0")
        bool is_connected;      // 连接状态标志
    
    public:
        // 构造函数
        controller(const std::string& iface) 
            : m_interface(iface), m_sock(-1), is_connected(false) 
        {

        }
    
        // 析构函数
        ~controller() 
        {
            disconnect();
        }
    
        // 禁用拷贝构造和赋值操作
        controller(const controller&) = delete;
        controller& operator=(const controller&) = delete;
    
        // 移动构造和赋值
        controller(controller&& other) noexcept 
            : m_sock(other.m_sock),
              m_interface(std::move(other.m_interface)),
              is_connected(other.is_connected) 
        {
            other.m_sock = -1;
            other.is_connected = false;
        }
    
        controller& operator=(controller&& other) noexcept 
        {
            if (this != &other) {
                disconnect();
                m_sock = other.m_sock;
                m_interface = std::move(other.m_interface);
                is_connected = other.is_connected;
                other.m_sock = -1;
                other.is_connected = false;
            }
            return *this;
        }
    
        /**
         * @brief 连接到CAN总线（仅创建并绑定套接字，不配置设备）
         * @note 调用前需确保CAN设备已通过系统命令配置好（波特率、已启动）
         * @return 成功返回true，失败抛出异常
         */
        bool connect() 
        {
            if (is_connected) return true;
    
            // 创建RAW CAN套接字
            m_sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
            if (m_sock < 0) {
                throw std::runtime_error("创建CAN套接字失败: " + std::string(strerror(errno)));
            }
    
            // 设置CAN接口并获取索引
            struct ifreq ifr;
            strncpy(ifr.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
            ifr.ifr_name[IFNAMSIZ - 1] = '\0';
    
            if (ioctl(m_sock, SIOCGIFINDEX, &ifr) < 0) {
                close(m_sock);
                m_sock = -1;
                throw std::runtime_error("获取CAN接口索引失败: " + std::string(strerror(errno)));
            }
    
            // 绑定套接字到CAN接口
            struct sockaddr_can addr;
            memset(&addr, 0, sizeof(addr));
            addr.can_family = AF_CAN;
            addr.can_ifindex = ifr.ifr_ifindex;
    
            if (bind(m_sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
                close(m_sock);
                m_sock = -1;
                throw std::runtime_error("绑定CAN套接字失败: " + std::string(strerror(errno)));
            }

            // set nonblock
            int flags = fcntl(m_sock, F_GETFL, 0);
            fcntl(m_sock, F_SETFL, flags | O_NONBLOCK);
    
            is_connected = true;
            return true;
        }
    
        /**
         * @brief 断开与CAN总线的连接
         */
        void disconnect() 
        {
            if (is_connected) 
            {
                close(m_sock);
                m_sock = -1;
                is_connected = false;
            }
        }
    
        /**
         * @brief 发送CAN帧
         * @param id CAN帧ID
         * @param data 数据缓冲区
         * @param len 数据长度(0-8)
         * @param is_extended 是否为扩展帧
         * @return 成功返回true，失败返回false
         */
        bool send(uint32_t id, const uint8_t* data, uint8_t len, bool is_extended = false) 
        {
            if (!is_connected || len > 8 || !data) return false;
    
            struct can_frame frame;
            memset(&frame, 0, sizeof(frame));
    
            // 设置帧ID和类型
            if (is_extended) {
                frame.can_id = id | CAN_EFF_FLAG;  // 扩展帧标志
            } else {
                frame.can_id = id & CAN_SFF_MASK;  // 标准帧ID掩码(0-0x7FF)
            }
    
            // 设置数据长度和内容
            frame.can_dlc = len;
            memcpy(frame.data, data, len);
    
            // 发送帧
            ssize_t bytes_sent = write(m_sock, &frame, sizeof(frame));
            return (bytes_sent == sizeof(frame));
        }
    
        /**
         * @brief 接收CAN帧
         * @param id 输出参数，接收的帧ID
         * @param data 输出缓冲区，用于存储接收的数据
         * @param len 输出参数，接收的数据长度
         * @param is_extended 输出参数，是否为扩展帧
         * @param timeout_us 超时时间(microsecends)，0表示无限等待
         * @return 成功返回true，超时或失败返回false
         */
        bool receive(uint32_t& id, uint8_t* data, uint8_t& len, bool& is_extended, int timeout_us = 0) 
        {
            if (!is_connected || !data) return false;
    
            // 设置接收超时
            if (timeout_us > 0)
            {
                fd_set rfds;
                FD_ZERO(&rfds);
                FD_SET(m_sock, &rfds);
    
                timeval timeout = {0, timeout_us};
                
                int ret = select(m_sock + 1, &rfds, nullptr, nullptr, &timeout);
                if (ret <= 0)
                {
                    return false;
                }
            }
            
            struct can_frame frame;
            ssize_t bytes_read = read(m_sock, &frame, sizeof(frame));
            if (bytes_read != sizeof(frame)) 
            {
                return false;
            }
            
            // 解析帧信息
            is_extended = (frame.can_id & CAN_EFF_FLAG) != 0;
            id = is_extended ? (frame.can_id & CAN_EFF_MASK) : (frame.can_id & CAN_SFF_MASK);
            len = frame.can_dlc;
            memcpy(data, frame.data, len);
    
            return true;
        }
    
        /**
         * @brief 检查连接状态
         * @return 已连接返回true，否则返回false
         */
        bool isConnected() const 
        {
            return is_connected;
        }
    
        /**
         * @brief 获取当前使用的CAN接口
         * @return 接口名称
         */
        std::string getInterface() const 
        {
            return m_interface;
        }
    };
} // namespace can